$OpenBSD: patch-src_ck-sysdeps-openbsd_c,v 1.19 2015/02/25 10:35:06 ajacoutot Exp $
--- src/ck-sysdeps-openbsd.c.orig	Wed Feb 25 07:05:22 2015
+++ src/ck-sysdeps-openbsd.c	Wed Feb 25 07:07:52 2015
@@ -0,0 +1,467 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
+ * Copyright (C) 2007 Joe Marcus Clarke <marcus@FreeBSD.org>
+ * Copyright (C) 2008 Jared D. McNeill <jmcneill@NetBSD.org>
+ * Copyright (C) 2009 Robert Nagy <robert@openbsd.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <paths.h>
+#include <ttyent.h>
+#include <kvm.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+
+#ifdef __OpenBSD__
+#include <sys/stdint.h>
+#endif
+
+#include <dev/wscons/wsdisplay_usl_io.h>
+
+#define DEV_ENCODE(M,m) ( \
+  ( (M&0xfff) << 8) | ( (m&0xfff00) << 12) | (m&0xff) \
+)
+
+#include "ck-sysdeps.h"
+
+#ifndef ERROR
+#define ERROR -1
+#endif
+
+/* adapted from procps */
+struct _CkProcessStat
+{
+        int pid;
+        int ppid;                       /* stat,status     pid of parent process */
+        char state;                     /* stat,status     single-char code for process state (S=sleeping) */
+        char cmd[16];                   /* stat,status     basename of executable file in call to exec(2) */
+        unsigned long long utime;       /* stat            user-mode CPU time accumulated by process */
+        unsigned long long stime;       /* stat            kernel-mode CPU time accumulated by process */
+        unsigned long long cutime;      /* stat            cumulative utime of process and reaped children */
+        unsigned long long cstime;      /* stat            cumulative stime of process and reaped children */
+        unsigned long long start_time;  /* stat            start time of process -- seconds since 1-1-70 */
+        unsigned long start_code;       /* stat            address of beginning of code segment */
+        unsigned long end_code;         /* stat            address of end of code segment */
+        unsigned long start_stack;      /* stat            address of the bottom of stack for the process */
+        unsigned long kstk_esp;         /* stat            kernel stack pointer */
+        unsigned long kstk_eip;         /* stat            kernel instruction pointer */
+        unsigned long wchan;            /* stat (special)  address of kernel wait channel proc is sleeping in */
+        long priority;                  /* stat            kernel scheduling priority */
+        long nice;                      /* stat            standard unix nice level of process */
+        long rss;                       /* stat            resident set size from /proc/#/stat (pages) */
+        long alarm;                     /* stat            ? */
+        unsigned long rtprio;           /* stat            real-time priority */
+        unsigned long sched;            /* stat            scheduling class */
+        unsigned long vsize;            /* stat            number of pages of virtual memory ... */
+        unsigned long rss_rlim;         /* stat            resident set size limit? */
+        unsigned long flags;            /* stat            kernel flags for the process */
+        unsigned long min_flt;          /* stat            number of minor page faults since process start */
+        unsigned long maj_flt;          /* stat            number of major page faults since process start */
+        unsigned long cmin_flt;         /* stat            cumulative min_flt of process and child processes */
+        unsigned long cmaj_flt;         /* stat            cumulative maj_flt of process and child processes */
+        int     pgrp;                   /* stat            process group id */
+        int session;                    /* stat            session id */
+        int nlwp;                       /* stat    number of threads, or 0 if no clue */
+        int tty;                        /* stat            full device number of controlling terminal */
+        int tpgid;                      /* stat            terminal process group id */
+        int exit_signal;                /* stat            might not be SIGCHLD */
+        int processor;                  /* stat            current (or most recent?) CPU */
+        uintptr_t penv;                 /* stat            address of initial environment vector */
+        char tty_text[11];              /* stat            device name */
+
+};
+
+pid_t
+ck_process_stat_get_ppid (CkProcessStat *stat)
+{
+        g_return_val_if_fail (stat != NULL, -1);
+
+        return stat->ppid;
+}
+
+char *
+ck_process_stat_get_cmd (CkProcessStat *stat)
+{
+        g_return_val_if_fail (stat != NULL, NULL);
+
+        return g_strdup (stat->cmd);
+}
+
+char *
+ck_process_stat_get_tty (CkProcessStat *stat)
+{
+        g_return_val_if_fail (stat != NULL, NULL);
+
+        return g_strdup (stat->tty_text);
+}
+
+static gboolean
+get_kinfo_proc (pid_t pid,
+                struct kinfo_proc *p)
+{
+        size_t len;
+
+        int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid,
+                      sizeof(struct kinfo_proc), 1 };
+
+#ifndef nitems
+#define nitems(_a)      (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+        len = sizeof(*p);
+        if (sysctl(mib, nitems(mib), p, &len, NULL, 0) < 0)
+            return FALSE;
+
+        return TRUE;
+}
+
+/* return 1 if it works, or 0 for failure */
+static gboolean
+stat2proc (pid_t        pid,
+           CkProcessStat *P)
+{
+        struct kinfo_proc p;
+        char              *ttname;
+        int               num;
+        int               tty_maj;
+        int               tty_min;
+
+        if (! get_kinfo_proc (pid, &p)) {
+                return FALSE;
+        }
+
+        num = KI_MAXCOMLEN;
+        if (num >= sizeof P->cmd) {
+                num = sizeof P->cmd - 1;
+        }
+
+        memcpy (P->cmd, p.p_comm, num);
+
+        P->cmd[num]   = '\0';
+        P->pid        = p.p_pid;
+        P->ppid       = p.p_ppid;
+        P->pgrp       = p.p__pgid;
+        P->session    = p.p_sid;
+        P->rss        = p.p_vm_rssize;
+        P->vsize      = p.p_vm_dsize + p.p_vm_dsize + p.p_vm_ssize; /* XXX */
+        P->start_time = p.p_ustart_sec;
+        P->wchan      = (unsigned long) p.p_wchan;
+        P->state      = p.p_stat;
+        P->nice       = p.p_nice;
+        P->flags      = p.p_psflags;
+        P->tpgid      = p.p_tpgid;
+        P->processor  = p.p_cpuid;
+
+        /* we like it Linux-encoded :-) */
+        tty_maj = major (p.p_tdev);
+        tty_min = minor (p.p_tdev);
+        P->tty = DEV_ENCODE (tty_maj,tty_min);
+
+        snprintf (P->tty_text, sizeof P->tty_text, "%3d,%-3d", tty_maj, tty_min);
+
+        if (p.p_tdev != NODEV && (ttname = devname (p.p_tdev, S_IFCHR)) != NULL) {
+                memcpy (P->tty_text, ttname, sizeof (P->tty_text));
+        }
+
+        if (p.p_tdev == NODEV) {
+		/* XXX how do we associate X with its tty? */
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
+                memcpy (P->tty_text, "/dev/ttyC4", sizeof (P->tty_text));
+#else
+                memcpy (P->tty_text, "/dev/ttyC0", sizeof (P->tty_text));
+#endif
+        }
+
+        if (P->pid != pid) {
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+gboolean
+ck_process_stat_new_for_unix_pid (pid_t           pid,
+                                  CkProcessStat **stat,
+                                  GError        **error)
+{
+        gboolean       res;
+        CkProcessStat *proc;
+
+        g_return_val_if_fail (pid > 1, FALSE);
+
+        if (stat == NULL) {
+                return FALSE;
+        }
+
+        proc = g_new0 (CkProcessStat, 1);
+        proc->pid = pid;
+        res = stat2proc (pid, proc);
+        if (res) {
+                *stat = proc;
+        } else {
+                *stat = NULL;
+        }
+
+        return res;
+}
+
+void
+ck_process_stat_free (CkProcessStat *stat)
+{
+        g_free (stat);
+}
+
+GHashTable *
+ck_unix_pid_get_env_hash (pid_t pid)
+{
+        GHashTable       *hash = NULL;
+        char            **penv;
+        char              errbuf[_POSIX2_LINE_MAX];
+        kvm_t            *kd;
+        struct kinfo_proc p;
+        int               i;
+
+        kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf);
+        if (kd == NULL) {
+		g_warning ("kvm_openfiles failed: %s", errbuf);
+                return NULL;
+        }
+
+        if (! get_kinfo_proc (pid, &p)) {
+		g_warning ("get_kinfo_proc failed: %s", g_strerror (errno));
+		goto fail;
+        }
+
+        penv = kvm_getenvv (kd, &p, 0);
+        if (penv == NULL) {
+		g_warning ("kvm_getenvv failed: %s", kvm_geterr (kd));
+		goto fail;
+        }
+
+        hash = g_hash_table_new_full (g_str_hash,
+                                      g_str_equal,
+                                      g_free,
+                                      g_free);
+
+        for (i = 0; penv[i] != NULL; i++) {
+                char **vals;
+
+                if (!penv[i][0]) continue;
+
+                vals = g_strsplit (penv[i], "=", 2);
+                if (vals != NULL) {
+                        g_hash_table_insert (hash,
+                                             g_strdup (vals[0]),
+                                             g_strdup (vals[1]));
+                        g_strfreev (vals);
+                }
+        }
+
+fail:
+        kvm_close (kd);
+
+        return hash;
+}
+
+char *
+ck_unix_pid_get_env (pid_t       pid,
+                     const char *var)
+{
+        GHashTable *hash;
+        char       *val = NULL;
+
+        /*
+         * Would probably be more efficient to just loop through the
+         * environment and return the value, avoiding building the hash
+         * table, but this works for now.
+         */
+        hash = ck_unix_pid_get_env_hash (pid);
+        if (hash == NULL)
+            return val;
+        val  = g_strdup (g_hash_table_lookup (hash, var));
+        g_hash_table_destroy (hash);
+
+        return val;
+}
+
+uid_t
+ck_unix_pid_get_uid (pid_t pid)
+{
+        uid_t             uid;
+        gboolean          res;
+        struct kinfo_proc p;
+
+        g_return_val_if_fail (pid > 1, 0);
+
+        uid = -1;
+
+        res = get_kinfo_proc (pid, &p);
+
+        if (res) {
+                uid = p.p_uid;
+        }
+
+        return uid;
+}
+
+gboolean
+ck_unix_pid_get_login_session_id (pid_t  pid,
+                                  char **idp)
+{
+        g_return_val_if_fail (pid > 1, FALSE);
+
+        return FALSE;
+}
+
+gboolean
+ck_get_max_num_consoles (guint *num)
+{
+        int      max_consoles;
+        int      res;
+        gboolean ret;
+        struct ttyent *t;
+
+        ret = FALSE;
+        max_consoles = 0;
+
+        res = setttyent ();
+        if (res == 0) {
+                goto done;
+        }
+
+        while ((t = getttyent ()) != NULL) {
+                if (t->ty_status & TTY_ON && strncmp (t->ty_name, "ttyC", 4) == 0)
+                        max_consoles++;
+        }
+
+        /* Increment one more so that all consoles are properly counted
+         * this is arguable a bug in vt_add_watches().
+         */
+        max_consoles++;
+
+        ret = TRUE;
+
+        endttyent ();
+
+done:
+         if (num != NULL) {
+                *num = max_consoles;
+         }
+
+        return ret;
+}
+
+gboolean
+ck_supports_activatable_consoles (void)
+{
+        return TRUE;
+}
+
+char *
+ck_get_console_device_for_num (guint num)
+{
+        char *device;
+
+/* VT are only available on i386, amd64 and macppc */
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
+        /* The device number is always one less than the VT number. */
+        num--;
+#endif
+
+        device = g_strdup_printf ("/dev/ttyC%u", num);
+
+        return device;
+}
+
+gboolean
+ck_get_console_num_from_device (const char *device,
+                                guint      *num)
+{
+        guint    n;
+        gboolean ret;
+
+        n = 0;
+        ret = FALSE;
+
+        if (device == NULL) {
+                return FALSE;
+        }
+
+        if (sscanf (device, "/dev/ttyC%u", &n) == 1) {
+/* VT are only available on i386, amd64 and macppc */
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
+                /* The VT number is always one more than the device number. */
+                n++;
+#endif
+                ret = TRUE;
+        }
+
+        if (num != NULL) {
+                *num = n;
+        }
+
+        return ret;
+}
+
+gboolean
+ck_get_active_console_num (int    console_fd,
+                           guint *num)
+{
+        gboolean ret;
+        int      res;
+        int      active;
+
+        g_assert (console_fd != -1);
+
+        active = 0;
+        ret = FALSE;
+
+/* VT are only available on i386, amd64 and macppc */
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
+        res = ioctl (console_fd, VT_GETACTIVE, &active);
+        if (res == ERROR) {
+                perror ("ioctl VT_GETACTIVE");
+                goto out;
+        }
+
+        g_debug ("Active VT is: %d (ttyC%d)", active, active - 1);
+#else
+       res = 0;
+       g_debug ("Active console is: ttyC%d", active);
+#endif
+        ret = TRUE;
+
+ out:
+        if (num != NULL) {
+                *num = active;
+        }
+
+        return ret;
+}
